package com.da.core.app;

import com.da.core.util.Utils;
import com.da.core.container.*;
import com.da.core.container.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author Da
 * @Description: 三十年生死两茫茫，写程序，到天亮。
 * 千行代码，Bug何处藏。
 * 纵使上线又怎样，朝令改，夕断肠。
 * 领导每天新想法，天天改，日日忙。
 * 相顾无言，惟有泪千行。
 * 每晚灯火阑珊处，夜难寐，又加班。
 * @Date 2023/7/23 上午 7:58
 */
public class FastDApp {
    private final DApp server;
    private final BeanContainer beanContainer;

    public <T> FastDApp(Class<T> app, BaseApp coreApp) {
        server = new DApp(coreApp);
        final String scanPackage = app.getPackage().getName();
//        bean容器
        beanContainer = new BeanContainer();
//        扫描bean,处理扫描出来的.class文件
        new ComponentScanner().scan(scanPackage, clazz ->
        {
            try {
                if (clazz.isAnnotationPresent(Component.class)) {
                    Component component = clazz.getAnnotation(Component.class);
                    String beanName = component.value();
                    if (beanName.isEmpty()) {
                        beanName = clazz.getSimpleName();
                    }
                    Object bean = clazz.newInstance();
                    beanContainer.addBean(beanName, bean);
                } else {
//                    处理路由bean
                    handlerPathBean(server, clazz);
                }
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
                     InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        });
//        简单的属性注入
        injectField();
    }

    // 端口和是否使用 Bio 模式
    public DApp run(int port) {
        server.setPort(port);
        server.start();
        return server;
    }

    public DApp run() {
        server.start();
        return server;
    }

    //    获取扫描出来的容器中的类
    public Object getBean(String beanName) {
        return beanContainer.getBean(beanName);
    }

    @SuppressWarnings("unchecked") // 让编译器不报黄线
    public <T> T getBean(String beanName, Class<T> t) {
        if (null != getBean(beanName)) {
            return (T) getBean(beanName);
        }
        return null;
    }

    enum HttpMethod {
        GET,
        POST,
        PUT,
        DELETE,
        SSE
    }

    private void handlerPathBean(DApp server, Class<?> clazz) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Map<Class<? extends Annotation>, HttpMethod> annotationToMethod = new HashMap<Class<? extends Annotation>, HttpMethod>(4) {
        };
        annotationToMethod.put(Get.class, HttpMethod.GET);
        annotationToMethod.put(Post.class, HttpMethod.POST);
        annotationToMethod.put(Put.class, HttpMethod.PUT);
        annotationToMethod.put(Delete.class, HttpMethod.DELETE);
        annotationToMethod.put(SSE.class, HttpMethod.SSE);

        for (Map.Entry<Class<? extends Annotation>, HttpMethod> entry : annotationToMethod.entrySet()) {
            Class<? extends Annotation> annotationClass = entry.getKey();
            HttpMethod httpMethod = entry.getValue();
            if (clazz.isAnnotationPresent(annotationClass)) {
                final Annotation annotation = clazz.getAnnotation(annotationClass);
//                获取路由路径
                final String path = (String) annotation.getClass().getMethod("value").invoke(annotation);
//                获取路由处理方法
                final Handler handlerFunc = (Handler) clazz.newInstance();
//                注册对应的方法
                switch (httpMethod) {
                    case GET:
                        server.GET(path, handlerFunc);
                        break;
                    case POST:
                        server.POST(path, handlerFunc);
                        break;
                    case PUT:
                        server.PUT(path, handlerFunc);
                        break;
                    case DELETE:
                        server.DELETE(path, handlerFunc);
                        break;
                    case SSE:
                        server.SSE(path, handlerFunc);
                        break;
                    default:
                        break;
                }
//                匹配到了就不用继续匹配了,继续去处理下一个clazz
                break;
            }
        }
    }

    //    把保存的bean中的属性注入
    public void injectField() {
        final Map<String, Object> beans = beanContainer.getBeans();
        beans.forEach((beanName, bean) ->
        {
            Class<?> clazz = bean.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Inject.class)) {
                    Inject inject = field.getAnnotation(Inject.class);
                    String value = inject.value();
                    Object fieldValue;
                    if (beans.containsKey(value)) {
                        if (beanName.equals(value)) {
                            throw new RuntimeException("不能自己注入自己 " + field.getType());
                        } else {
                            fieldValue = beans.get(value);
                        }
                    } else {
                        fieldValue = Utils.convertToFieldType(inject.value(), field.getType());
                    }
                    field.setAccessible(true);
                    try {
                        field.set(bean, fieldValue);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                    field.setAccessible(false);
                }
            }
        });
    }
}
